﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//zdm 2019.6.12
//寻路组件中使用的具体寻路策略
public enum Selector
{
    Base, Random, Back, Goal, Goto, Start, Left, Right, Player, Steal, StealBack
};

//基类寻路
public abstract class BaseSelector
{
    public BaseSelector()
    {

    }

    public static readonly int MAXBACK = 2;
    public int GOALDIST = 3;

    public int direct = 0;

    public abstract Vector2Int GetNextPos(Vector2Int pos);
    public void Update(Vector2Int pos) { prePos = pos; }
    public void SetDest(Vector2Int pos) { destPos = pos; }
    public int CheckBack() { return goBackTime; }
    
    private RandomGenerator rand;
    public Vector2Int prePos = ConstOfMap.ERRORPOS;
    public Vector2Int destPos = ConstOfMap.ERRORPOS;
    public int goBackTime;


    public static readonly int[] mx = new int[4] { 1, 0, -1, 0 };
    public static readonly int[] my = new int[4] { 0, -1, 0, 1 };
}

#region 随机游走
//默认寻路算法，随机游走
public class RandomSelect : BaseSelector
{
    public RandomSelect()
    {
        goBackTime = 0;
    }
    public override Vector2Int GetNextPos(Vector2Int pos)
    {
        if (pos == MapManager.Instance.goalPos)
            return pos;
        //临时保存mapmanager中的地图数据
        Vector2Int[] cse = new Vector2Int[4];
        int[] dis = new int[4];
        int count = 0;
        int disNow = MapManager.Instance.sDist[pos.x, pos.y];

        int randomKey = 0;

        //原则：尽可能向离起点更远的方向前进，同时存在多个时随机选择，最后再考虑回头

        for (int i = 0; i < 4; i++)
        {
            Vector2Int nextPos = new Vector2Int(pos.x + mx[i], pos.y + my[i]);
            if (MapManager.Instance.IsRoad(nextPos))
            {
                cse[count] = nextPos;
                dis[count] = MapManager.Instance.sDist[nextPos.x, nextPos.y];
                if (nextPos != prePos)
                    randomKey += dis[count] - disNow + 1;
                ++count;
            }
        }
        if (randomKey != 0)
        {
            int check = RandomGenerator.Instance.Next(randomKey);
            for (int i = 0; i < count; i++)
            {
                Vector2Int nextPos = cse[i];
                if (nextPos != prePos && dis[i] > disNow)
                {
                    if (check < 2)
                    {
                        return nextPos;
                    }
                    else check -= 2;
                }
            }
            ++goBackTime;
            return prePos;
        }
        else
        {
            ++goBackTime;
            if(count > 1)
            {
                int check = RandomGenerator.Instance.Next(count - 1);
                for (int i = 0; i < count; i++)
                {
                    Vector2Int nextPos = cse[i];
                    if (nextPos != prePos)
                    {
                        if (check == 0)
                        {
                            return nextPos;
                        }
                        else check--;
                    }
                }
            }
            return prePos;
        }
    }
}
#endregion

#region 原路返回
//默认寻路算法，原路返回
public class GoBack : BaseSelector
{
    public GoBack(int tim = 0)
    {
        goBackTime = MAXBACK + 2 * tim;
    }
    public override Vector2Int GetNextPos(Vector2Int pos)
    {
        if (pos == MapManager.Instance.goalPos)
            return pos;
        //临时保存mapmanager中的地图数据
        Vector2Int[] cse = new Vector2Int[4];
        Vector2Int[] sce = new Vector2Int[4];
        int[] dis = new int[4];
        int count = 0;
        int scount = 0;
        int disNow = MapManager.Instance.sDist[pos.x, pos.y];

        //原则：尽可能向正确路径上移动（离终点更近），否则向离起点更近的方向移动，最后再考虑回头

        for (int i = 0; i < 4; i++)
        {
            Vector2Int nextPos = new Vector2Int(pos.x + mx[i], pos.y + my[i]);
            if (MapManager.Instance.IsRoad(nextPos))
            {
                cse[count] = nextPos;
                dis[count] = MapManager.Instance.sDist[nextPos.x, nextPos.y];
                if(nextPos != prePos && MapManager.Instance.tDist[nextPos.x, nextPos.y] == MapManager.Instance.tDist[pos.x, pos.y] - 1)
                {
                    sce[scount] = nextPos;
                    ++scount;
                }
                ++count;
            }
        }
        if(scount != 0)
        {
            int check = RandomGenerator.Instance.Next(scount);
            for(int i = 0; i < scount; i++)
            {
                Vector2Int nextPos = sce[i];
                if (check <= 0)
                {
                    if(MapManager.Instance.sDist[nextPos.x, nextPos.y] > disNow)
                        --goBackTime;
                    return sce[i];
                }
                else --check;
            }
        }
        if(count > 1)
        {
            int check = RandomGenerator.Instance.Next(count - 1);
            for (int i = 0; i < count; i++)
            {
                Vector2Int nextPos = cse[i];
                if (nextPos != prePos && dis[i] == disNow - 1 && check <= 0)
                {
                    return nextPos;
                }
                else --check;
            }
        }
        return prePos;
    }
}
#endregion

#region 接近终点
//默认寻路算法，向终点靠近
public class GoToGoal : BaseSelector
{
    public GoToGoal()
    {
        goBackTime = 0;
    }
    public override Vector2Int GetNextPos(Vector2Int pos)
    {
        if (pos == MapManager.Instance.goalPos)
            return pos;
        //临时保存mapmanager中的地图数据
        Vector2Int[] cse = new Vector2Int[4];
        int[] dis = new int[4];
        int count = 0;
        int disNow = MapManager.Instance.tDist[pos.x, pos.y];

        int randomKey = 0;

        //原则：尽可能向离终点更近的方向前进，同时存在多个时随机选择，不考虑回头检定

        for (int i = 0; i < 4; i++)
        {
            Vector2Int nextPos = new Vector2Int(pos.x + mx[i], pos.y + my[i]);
            if (MapManager.Instance.IsRoad(nextPos))
            {
                cse[count] = nextPos;
                dis[count] = MapManager.Instance.tDist[nextPos.x, nextPos.y];
                randomKey += disNow - dis[count] + 1;
                ++count;
            }
        }
        if (randomKey != 0)
        {
            int check = RandomGenerator.Instance.Next(randomKey);
            for (int i = 0; i < count; i++)
            {
                Vector2Int nextPos = cse[i];
                if (dis[i] < disNow)
                {
                    if (check < 2)
                    {
                        return nextPos;
                    }
                    else check -= 2;
                }
            }
            return prePos;
        }
        else
        {
            if(count > 1)
            {
                int check = RandomGenerator.Instance.Next(count - 1);
                for (int i = 0; i < count; i++)
                {
                    Vector2Int nextPos = cse[i];
                    if (check == 0)
                    {
                        return nextPos;
                    }
                    else check--;
                }
            }
            return prePos;
        }
    }
}
#endregion

#region 走向定点
//默认寻路算法，向指定点前进
public class GoToSomewhere : BaseSelector
{
    public GoToSomewhere()
    {
        goBackTime = 0;
    }
    public override Vector2Int GetNextPos(Vector2Int pos)
    {
        if (pos == destPos)
            return pos;
        //原则：尽可能向减小xy差值的方向移动，因此该寻路模式仅适用于已经看到指定点的场合

        int deltaX = destPos.x - pos.x, deltaY = destPos.y - pos.y;
        if(deltaX != 0)
            deltaX = deltaX / System.Math.Abs(deltaX);
        if(deltaY != 0)
            deltaY = deltaY / System.Math.Abs(deltaY);
        int way = RandomGenerator.Instance.Next(2);
        for (int i = 0; i < 2; i++)
        {
            if(way == 0 && deltaX != 0)
            {
                Vector2Int nextPos = new Vector2Int(pos.x + deltaX, pos.y);
                if(MapManager.Instance.IsRoad(nextPos))
                {
                    return nextPos;
                }
            }
            else if(deltaY != 0)
            {
                Vector2Int nextPos = new Vector2Int(pos.x, pos.y + deltaY);
                if (MapManager.Instance.IsRoad(nextPos))
                {
                    return nextPos;
                }
            }
            way = (way + 1) % 2;
        }
        return prePos;
    }
}
#endregion

#region 接近起点
//默认寻路算法，向起点前进
public class GoToStart : BaseSelector
{
    public GoToStart()
    {
        goBackTime = 0;
    }
    public override Vector2Int GetNextPos(Vector2Int pos)
    {
        if (pos == MapManager.Instance.enterPos)
            return pos;
        //Debug.Log(pos.ToString());
        Vector2Int[] cse = new Vector2Int[4];
        int[] dis = new int[4];
        int count = 0;
        int disNow = MapManager.Instance.sDist[pos.x, pos.y];
        int randomKey = 0;

        //原则：尽可能向离起点更近的方向移动，存在多个时随机选择，不考虑回头判定

        for (int i = 0; i < 4; i++)
        {
            Vector2Int nextPos = new Vector2Int(pos.x + mx[i], pos.y + my[i]);
            if(MapManager.Instance.IsRoad(nextPos))
            {
                cse[count] = nextPos;
                dis[count] = MapManager.Instance.sDist[nextPos.x, nextPos.y];
                randomKey += disNow - dis[count] + 1;
                ++count;
            }
        }
        if (randomKey != 0)
        {
            int check = RandomGenerator.Instance.Next(randomKey);
            for (int i = 0; i < count; i++)
            {
                Vector2Int nextPos = cse[i];
                if (dis[i] < disNow)
                {
                    if (check < 2)
                    {
                        return nextPos;
                    }
                    else check -= 2;
                }
            }
            return prePos;
        }
        else
        {
            if (count > 1)
            {
                int check = RandomGenerator.Instance.Next(count - 1);
                for (int i = 0; i < count; i++)
                {
                    Vector2Int nextPos = cse[i];
                    if (check == 0)
                    {
                        return nextPos;
                    }
                    else check--;
                }
            }
            return prePos;
        }
    }
}
#endregion

#region 左手优先
//特有寻路算法，左手优先
public class GoLeft : BaseSelector
{
    public GoLeft()
    {
        goBackTime = 0;
    }
    public override Vector2Int GetNextPos(Vector2Int pos)
    {
        if (pos == MapManager.Instance.goalPos)
            return pos;
        for (int i = 0; i < 4; i++)
        {
            int ri = (i + direct + 3) % 4;
            Vector2Int nextPos = new Vector2Int(pos.x + mx[ri], pos.y + my[ri]);
            if(MapManager.Instance.IsRoad(nextPos))
            {
                direct = ri;
                if (i == 0)
                    ++goBackTime;
                return nextPos;
            }
        }
        return prePos;
    }
}
#endregion

#region 右手优先
//特有寻路算法，左手优先
public class GoRight : BaseSelector
{
    public GoRight()
    {
        goBackTime = 0;
    }
    public override Vector2Int GetNextPos(Vector2Int pos)
    {
        if (pos == MapManager.Instance.goalPos)
            return pos;
        for (int i = 0; i < 4; i++)
        {
            int ri = (5 - i + direct) % 4;
            Vector2Int nextPos = new Vector2Int(pos.x + mx[ri], pos.y + my[ri]);
            if (MapManager.Instance.IsRoad(nextPos))
            {
                direct = ri;
                if (i == 0)
                    ++goBackTime;

                return nextPos;
            }
        }
        return prePos;
    }
}
#endregion

#region 接近玩家
//特有寻路算法，向玩家前进
public class GoPlayer : BaseSelector
{
    public GoPlayer()
    {
        goBackTime = 0;
        GOALDIST = 0;
    }
    public override Vector2Int GetNextPos(Vector2Int pos)
    {
        if (pos == MapManager.Instance.playerPos)
            return pos;
        //临时保存mapmanager中的地图数据
        Vector2Int[] cse = new Vector2Int[4];
        int[] dis = new int[4];
        int count = 0;
        int mad = 100000000;

        //原则：尽可能向离玩家更近的方向前进，同时存在多个时随机选择，不考虑回头检定

        for (int i = 0; i < 4; i++)
        {
            Vector2Int nextPos = new Vector2Int(pos.x + mx[i], pos.y + my[i]);
            if (MapManager.Instance.IsRoad(nextPos))
            {
                cse[count] = nextPos;
                dis[count] = MapManager.Instance.pDistIgnoreTower[nextPos.x, nextPos.y];
                if (mad > dis[count])
                    mad = dis[count];
                ++count;
            }
        }

        int randomKey = 0;

        for (int i = 0; i < count; i++)
        {
            if (dis[i] == mad)
            {
                cse[randomKey] = cse[i];
                dis[randomKey] = dis[i];
                ++randomKey;
            }
        }

        if (randomKey != 0)
        {
            int check = RandomGenerator.Instance.Next(randomKey);
            for (int i = 0; i < count; i++)
            {
                Vector2Int nextPos = cse[i];
                if (check < 1)
                {
                    return nextPos;
                }
                else check -= 1;
            }
            return prePos;
        }
        else
        {
            return prePos;
        }
    }
}
#endregion

#region 偷家优先
//特有寻路算法，尽可能避开防御塔向终点靠近
public class StealHome : BaseSelector
{
    public StealHome()
    {
        goBackTime = 0;
        GOALDIST = 1;
    }
    public override Vector2Int GetNextPos(Vector2Int pos)
    {
        if (pos == MapManager.Instance.goalPos)
            return pos;
        //临时保存mapmanager中的地图数据
        Vector2Int[] cse = new Vector2Int[4];
        int[] dis = new int[4];
        int count = 0;
        int mad = 100000000;

        //原则：尽可能向离终点更近的方向前进，同时存在多个时随机选择，不考虑回头检定

        for (int i = 0; i < 4; i++)
        {
            Vector2Int nextPos = new Vector2Int(pos.x + mx[i], pos.y + my[i]);
            if (MapManager.Instance.IsRoad(nextPos))
            {
                cse[count] = nextPos;
                dis[count] = MapManager.Instance.tDistIgnoreTower[nextPos.x, nextPos.y];
                if (mad > dis[count])
                    mad = dis[count];
                ++count;
            }
        }

        int randomKey = 0;

        for (int i = 0; i < count; i++)
        {
            if (dis[i] == mad)
            {
                cse[randomKey] = cse[i];
                dis[randomKey] = dis[i];
                ++randomKey;
            }
        }

        if (randomKey != 0)
        {
            int check = RandomGenerator.Instance.Next(randomKey);
            for (int i = 0; i < count; i++)
            {
                Vector2Int nextPos = cse[i];
                if (check < 1)
                {
                    return nextPos;
                }
                else check -= 1;
            }
            return prePos;
        }
        else
        {
            return prePos;
        }
    }
}
#endregion

#region 偷家回城
//特有寻路算法，避开防御塔向起点前进
public class StealStart : BaseSelector
{
    public StealStart()
    {
        goBackTime = 0;
        GOALDIST = 0;
    }
    public override Vector2Int GetNextPos(Vector2Int pos)
    {
        if (pos == MapManager.Instance.playerPos)
            return pos;
        //临时保存mapmanager中的地图数据
        Vector2Int[] cse = new Vector2Int[4];
        int[] dis = new int[4];
        int count = 0;
        int mad = 100000000;

        //原则：尽可能向离起点更近的方向前进，同时存在多个时随机选择，不考虑回头检定

        for (int i = 0; i < 4; i++)
        {
            Vector2Int nextPos = new Vector2Int(pos.x + mx[i], pos.y + my[i]);
            if (MapManager.Instance.IsRoad(nextPos))
            {
                cse[count] = nextPos;
                dis[count] = MapManager.Instance.sDistIgnoreTower[nextPos.x, nextPos.y];
                if (mad > dis[count])
                    mad = dis[count];
                ++count;
            }
        }

        int randomKey = 0;

        for (int i = 0; i < count; i++)
        {
            if (dis[i] == mad)
            {
                cse[randomKey] = cse[i];
                dis[randomKey] = dis[i];
                ++randomKey;
            }
        }

        if (randomKey != 0)
        {
            int check = RandomGenerator.Instance.Next(randomKey);
            for (int i = 0; i < count; i++)
            {
                Vector2Int nextPos = cse[i];
                if (check < 1)
                {
                    return nextPos;
                }
                else check -= 1;
            }
            return prePos;
        }
        else
        {
            return prePos;
        }
    }
}
#endregion
